using System;
using System.IO;
using System.Net.Sockets;
using Microsoft.Extensions.Logging;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using RabbitMQ.Client.Exceptions;

namespace BuildingBlocks.Infrastructure.EventBus.RabbitMQ
{
    public class DefaultRabbitMQPersistentConnection : IRabbitMQPersistentConnection, IDisposable
    {
        private readonly IConnectionFactory _connectionFactory;
        private readonly ILogger<DefaultRabbitMQPersistentConnection> _logger;
        private IConnection? _connection;
        private bool _disposed;
        private readonly object _lock = new object();

        public DefaultRabbitMQPersistentConnection(
            IConnectionFactory connectionFactory,
            ILogger<DefaultRabbitMQPersistentConnection> logger)
        {
            _connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        public bool IsConnected => _connection != null && _connection.IsOpen && !_disposed;

        public IModel CreateModel()
        {
            if (!IsConnected)
            {
                throw new InvalidOperationException("没有可用的 RabbitMQ 连接，请先调用 TryConnect。");
            }
            return _connection!.CreateModel();
        }

        public bool TryConnect()
        {
            _logger.LogInformation("正在尝试连接到 RabbitMQ...");

            lock (_lock)
            {
                try
                {
                    _connection = _connectionFactory.CreateConnection();
                }
                catch (BrokerUnreachableException ex)
                {
                    _logger.LogError(ex, "RabbitMQ 无法连接。");
                    return false;
                }

                if (IsConnected)
                {
                    _logger.LogInformation("RabbitMQ 连接成功到 '{HostName}'。", _connection.Endpoint.HostName);

                    // 注册断开连接的事件
                    _connection.ConnectionShutdown += OnConnectionShutdown;
                    _connection.CallbackException += OnCallbackException;
                    _connection.ConnectionBlocked += OnConnectionBlocked;

                    return true;
                }
                else
                {
                    _logger.LogCritical("RabbitMQ 连接失败。");
                    return false;
                }
            }
        }

        private void OnConnectionBlocked(object? sender, ConnectionBlockedEventArgs e)
        {
            if (_disposed) return;
            _logger.LogWarning("RabbitMQ 连接被阻塞。尝试重连...");
            TryConnect();
        }

        private void OnCallbackException(object? sender, CallbackExceptionEventArgs e)
        {
            if (_disposed) return;
            _logger.LogWarning("RabbitMQ 回调异常。尝试重连...");
            TryConnect();
        }

        private void OnConnectionShutdown(object? sender, ShutdownEventArgs reason)
        {
            if (_disposed) return;
            _logger.LogWarning("RabbitMQ 连接关闭。尝试重连...");
            TryConnect();
        }

        public void Dispose()
        {
            if (_disposed) return;
            _disposed = true;

            try
            {
                _connection?.Dispose();
            }
            catch (IOException ex)
            {
                _logger.LogCritical(ex, "关闭 RabbitMQ 连接时出错。");
            }
        }
    }
}
